package openai

import (
	"chatgpt/config"
	"chatgpt/helper"
	"chatgpt/helper/code"
	"chatgpt/plugin/dirtywords"
	"context"
	gogpt "github.com/sashabaranov/go-openai"
	"github.com/slclub/glog"
	"github.com/slclub/go-tips"
	"net/http"
	"strings"
	"sync"
)

type AppGPT struct {
	mu     sync.Locker
	client *gogpt.Client
}

func (self *AppGPT) Client() *gogpt.Client {
	if self.client != nil {
		return self.client
	}
	cnf := self.Config()
	self.client = gogpt.NewClient(cnf.ApiKey)
	return self.client
}

func (self *AppGPT) Completion(question *Request) *ResponseCompletion {
	ctx := context.Background()
	response := &ResponseCompletion{
		MsgCode: code.SUCCESS,
	}
	if question.Text == "" {
		response.MsgCode = code.DATA_NIL
		glog.Errorf("CHATGPT.Completion.REQ.TEXT is empty!")
		return response
	}

	cnf := self.Config()
	prompt := question.Text
	if len(cnf.Davinci.BotDesc) > 0 {
		prompt = cnf.Davinci.BotDesc + " " + question.Text
	}
	model := question.Model
	if strings.Trim(model, " ") == "" {
		model = cnf.Davinci.Model
	}

	glog.Infof("CHATGPT.Completion.REQ prompt is %s with-model:%v ", prompt, model)
	req := gogpt.CompletionRequest{
		Model:            model,
		MaxTokens:        cnf.Davinci.MaxTokens,
		TopP:             cnf.Davinci.TopP,
		FrequencyPenalty: cnf.Davinci.FrequencyPenalty,
		PresencePenalty:  cnf.Davinci.PresencePenalty,
		Prompt:           prompt,
		Stop:             question.Stop,
	}
	//self.Client().CreateChatCompletionStream()
	resp, err := self.Client().CreateCompletion(ctx, req)
	response.resp = resp
	if err != nil {
		glog.Errorf("CHATGPT.Completion.RESPONSE.ERROR %v", err)
		response.MsgCode = code.DATA_CALL_ERROR
		return response
	}
	glog.Debugf("CHATGPT.Completion.RESPONSE.OK")
	return response
}

func (self *AppGPT) Config() *config.ChatGPTConf {
	cnf := config.ChatGPTConf{}
	cnf.Load()
	// 默认配置
	return &cnf
}

func (self *AppGPT) Conv(question string, model string, stop string) *Response {
	result := &Response{
		MsgCode: code.DATA_NIL,
	}
	if strings.Trim(question, " ") == "" {
		return result
	}
	stoparr := []string{}
	if stop != "" {
		stoparr = strings.Split(stop, ",")
	}
	res := AppChatGPT.Completion(&Request{Text: question, Model: model, Stop: stoparr})
	result.MsgCode = res.MsgCode
	if res.MsgCode != code.SUCCESS {
		return result
	}
	if res.MsgCode == code.SUCCESS && res.resp.Choices == nil {
		glog.Errorf("CHATGPT.CALL %v", "response.choice is nil")
		return result
	}
	result.Text = res.resp.Choices[0].Text

	//usage := res.resp.Usage
	if len(result.Text) > 2 && result.Text[:2] == "\n\n" {
		result.Text = result.Text[2:]
	}
	result.Tokens = res.resp.Usage.TotalTokens
	return result
}

func (self *AppGPT) CheckQuestion(question string) bool {
	if len([]rune(question)) < 3 {
		return true
	}
	if !dirtywords.DirtyWords().Contains(question) {
		return true
	}
	return false
}

func (self *AppGPT) Unsafe(questioin, model string) bool {
	if model == helper.UNSAFE_MOD {
		return true
	}
	if len(questioin) <= 2 {
		return true
	}
	if questioin[:2] == "@@" {
		return true
	}
	return false
}

// completion

func CompletionRemote(w http.ResponseWriter, m map[string]any) (code.CODENO, *helper.ResponseDesc) {
	dest := helper.ResponseDesc{MsgCode: code.SUCCESS}
	if val := tips.String(m["stream"]); val == "" {
		mm := helper.ConvMapAnyToMapString(&m)
		return RemoteApi(OPENAI_COMPLETION, tips.String(m["q"]), mm)
	}
	return RemoteStream(w, OPENAI_COMPLETION, m, &dest)
}
